<?php

namespace magein\think\command;

use magein\think\command\traits\CommandParamParse;

use magein\utils\Variable;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class MakeValidate extends Command
{
    use CommandParamParse;

    protected string $help = '
    1. 根据模型文件创建验证类到app/validate目录下
    2. 支持表名称模糊匹配
    
    php think model:validate user                      根据user表创建
    php think model:validate user_order                根据user_order表创建
';

    protected function configure()
    {
        // 指令配置
        $this->setName('model:validate')
            ->addArgument('name')
            ->addOption('index', 'i', Option::VALUE_OPTIONAL, '选择索引编号')
            ->setDescription('the model validate command')
            ->setHelp($this->help);
    }

    protected function execute(Input $input, Output $output)
    {
        if (\think\facade\Env::get('app_env') !== 'local') {
            $output->error('只能在开发环境中使用');
            exit();
        }

        $name = $input->getArgument('name');
        $index = $input->getOption('index');

        $result = $this->tableAttrs($name, intval($index));

        if ($result->getCode()) {
            $output->error($result->getMsg());
            return false;
        }

        $table_info = $result->getData();
        $table_name = $table_info['table_name'];
        $attrs = $table_info['attrs'];

        if ($attrs) {

            $data = $this->make($attrs);

            $this->write($table_name, $data, $output);
        }
    }

    /**
     * 构造文件内容
     * @param array $attrs
     * @return array
     */
    public function make(array $attrs): array
    {
        $rules = '';
        $messages = '';
        foreach ($attrs as $attr) {
            $field = $attr['Field'];
            $type = $attr['Type'];
            $comment = trim($attr['Comment']);

            if (in_array($field, ['id', 'created_at', 'updated_at', 'deleted_at'])) {
                continue;
            }

            $comments = explode(' ', $comment);
            $comment = current($comments);

            $concat = function ($rule, $desc) use ($field, $comment) {
                return "        '{$field}.{$rule}' => '" . $comment . $desc . "',";
            };

            if (is_null($attr['Default'])) {
                $rule = ['require'];
                $message = [
                    $concat('require', '必填')
                ];
            } else {
                $rule = [];
                $message = [];
            }

            if (in_array($field, ['email', 'ip', 'url'])) {
                $rule[] = $field;
                $message[] = $concat($field, '格式错误');
            } elseif (in_array($field, ['phone', 'mobile'])) {
                $rule[] = 'mobile';
                $message[] = $concat('mobile', '格式错误');
            } else {
                if (str_starts_with($type, 'int')) {
                    $rule[] = 'number';
                    $message[] = $concat('number', '为整型');
                }

                if (str_contains($type, 'varchar')) {
                    preg_match('/\(([0-9]+)\)/', $type, $matches);
                    $len = $matches[1] ?? 100;
                    if ($len <= 0) {
                        $len = 2;
                    }
                    $rule[] = 'length:1,' . $len;
                    $message[] = $concat('length', '长度为1~' . $len);
                }

                if (str_contains($type, 'datetime')) {
                    $rule[] = 'date';
                    $message[] = $concat('date', '需要一个日期格式');
                }

                if (str_contains($type, 'tinyint')) {
                    $range = array_filter($comments, function ($item) {
                        if (preg_match('/^[0-9]+$/', $item)) {
                            return true;
                        }
                        return false;
                    });
                    $rule[] = 'in:' . implode(',', $range);
                    $message[] = $concat('in', '可选值错误');
                }
            }

            $rule = implode('|', $rule);
            if (empty($rules)) {
                $rules .= sprintf("'%s' => '%s',", $field, $rule);
            } else {
                $rules .= sprintf("        '%s' => '%s',", $field, $rule);
            }
            $rules .= "\n";

            $messages .= implode("\n", $message) . "\n";
        }

        $rules = trim($rules, "\n");
        $messages = trim($messages, "\n");
        $messages = trim($messages);

        return compact('rules', 'messages');
    }

    /**
     * 写入文件
     * @param $name
     * @param $data
     * @param Output $output
     * @return void
     */
    protected function write($name, $data, Output $output)
    {
        $filepath = $this->filepath($name, 'validate', 'app/validate');
        if (!is_dir($filepath)) {
            $output->error($filepath . ',目录创建失败，请手动创建');
            exit();
        }

        // 文件名称
        $filename = $this->filename($name, 'validate');
        // 文件的命名空间
        $namespace = $this->namespace($filepath);

        $filepath .= Variable::pascal(trim($filename, '/')) . '.php';
        if (is_file($filepath)) {
            $output->error($filepath . '已经存在');
            exit();
        }

        // 类名称
        $cla_name = pathinfo($filepath, PATHINFO_FILENAME);
        $template = $this->template($cla_name, $data, $namespace);

        file_put_contents($filepath, $template);

        $message = '创建失败';
        if (is_file($filepath)) {
            $message = '创建成功';
        }

        $output->writeln($filepath . $message);
    }

    /**
     * @param $cla_name
     * @param $data
     * @param string $namespace
     * @return string
     */
    public function template($class_name, $data, string $namespace = 'app\validate'): string
    {
        $rules = $data['rules'] ?? '';
        $messages = $data['messages'] ?? '';

        $template = app()->config->get("console.config.validate.template", '') ?: dirname(__DIR__) . '/stubs/validate.stub';

        if (!is_file($template)) {
            return '';
        }

        $content = file_get_contents($template);

        return preg_replace(
            [
                '/\{\$namespace\}/',
                '/\{\$class_name\}/',
                '/\{\$rules\}/',
                '/\{\$messages\}/',
            ],
            [
                $namespace,
                $class_name,
                $rules,
                $messages,
            ],
            $content
        );
    }
}